grammar MathEvaluator;

options {
  language = Java;
}


@header {
  package id.co.rho.framework.math.evaluator;
  import java.math.BigDecimal;
  import id.co.rho.framework.math.evaluator.model.*;
}


@lexer::header { 
  package id.co.rho.framework.math.evaluator;
  import java.math.BigDecimal;
  import id.co.rho.framework.math.evaluator.model.*;
}

evaluator returns [MEValueNode res]
  : expression EOF {$res = $expression.res;};  

term returns [MEValueNode res]
	: 
	ID {$res = new LeafValueNode($ID.text);} 
	| '(' expression ')' {$res = $expression.res;}
	| FLOAT {$res = new LeafValueNode(new BigDecimal($FLOAT.text));} 
	| INT {$res = new LeafValueNode(new BigDecimal($INT.text));} 
	;
  
unary returns [MEValueNode res]  : 
	{boolean positive = true;}
  	('+' | '-' {positive=false;})* term {
  		$res = $term.res;
  		if(!positive) {
  			$res = new UnaryOpValueNode($res,Operator.UNARY_MIN);
  		}
  		} 
  ;

mult returns [MEValueNode res] :
  o1=unary {$res = $o1.res;}
  (
    '*' o2=unary {$res = new BinaryOpValueNode($res, $o2.res, Operator.MULT);}
    | '/' o3=unary {$res = new BinaryOpValueNode($res, $o3.res, Operator.DIV);}
    | 'mod' o4=unary {$res = new BinaryOpValueNode($res, $o4.res, Operator.MOD);}
  ) *
  ;

expression returns [MEValueNode res] :
  o1=mult {$res = $o1.res;}
  (
    '+' o2=mult {$res = new BinaryOpValueNode($res, $o2.res, Operator.ADD);}
    | '-'o3=mult {$res = new BinaryOpValueNode($res, $o3.res, Operator.SUB);}
  )*
  ;

ID  : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ('!' ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*)*
    ;

INT : '0'..'9'+ 
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

COMMENT
    :   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;
